import EventEmitter from "@/eventEmitter";
import { DrawInteractor } from "./drawInteractor/drawInteractor";
import { RectDrawInteractor } from "./drawInteractor/drawRectInteractor";
import { EllipseDrawInteractor } from "./drawInteractor/drawEllipseInteractor";
import { PolyLineDrawInteractor } from "./drawInteractor/drawPolyLineInteractor";
import { BezierCurveDrawInteractor } from "./drawInteractor/drawBezierCurveInteractor";
import { SelectedInteractor } from "./selectedInteractor";
import { GraphDataModel } from "./graphDataModel";
import GraphBase from "./shape/graphBase";
import { DrawTypeEnum } from "./enum";
import { throttle } from "./utils";
import { setScale } from "./graphviewState";
export default class GraphView extends EventEmitter {
  ctx: CanvasRenderingContext2D | null;
  dom: HTMLCanvasElement;
  interactor!: DrawInteractor | SelectedInteractor | null;
  dataModel: GraphDataModel;
  drawType: DrawTypeEnum = DrawTypeEnum.NO_DRAW;
  selectedObj: GraphBase | null = null;
  zoom: number = 1;
  constructor(width: number, height: number) {
    super();
    this.dom = document.createElement("canvas");
    this.dom.width = width;
    this.dom.height = height;
    this.dom.classList.add("graphview");
    this.ctx = this.dom.getContext("2d");
    this.dataModel = new GraphDataModel(this);
    this.onWheel = throttle(this.onWheel, 16, this);
    this.dom.addEventListener("wheel", this.onWheel);
  }
  setDrawInteractor(type: DrawTypeEnum) {
    this.drawType = type;
    this.interactor?.destroy();
    switch (type) {
      case DrawTypeEnum.NO_DRAW:
        this.interactor = new SelectedInteractor(this.dom, this.dataModel);
        this.onSelectedChange = this.onSelectedChange.bind(this);
        this.onPropertyChange = this.onPropertyChange.bind(this);
        this.interactor.on("selectedChange", this.onSelectedChange);
        this.interactor.on("propertyChange", this.onPropertyChange);
        break;
      case DrawTypeEnum.RECT_DRAW:
        this.interactor = new RectDrawInteractor(this.dom);
        break;
      case DrawTypeEnum.ELLIPSE_DRAW:
        this.interactor = new EllipseDrawInteractor(this.dom);
        break;
      case DrawTypeEnum.POLYLINE_DRAW:
        this.interactor = new PolyLineDrawInteractor(this.dom);
        break;
      case DrawTypeEnum.BEZIER_CURVE_DRAW:
        this.interactor = new BezierCurveDrawInteractor(this.dom);
        break;
      default:
        break;
    }
    if (this.interactor) {
      this.interactor.on("redraw", () => {
        this.redraw();
      });
      if (this.drawType !== DrawTypeEnum.NO_DRAW) {
        this.interactor.on("drawend", (node: GraphBase) => {
          this.drawEnd(node);
        });
      }
    }
  }
  getCtx() {
    return this.ctx;
  }
  redraw() {
    if (this.ctx) {
      this.ctx.clearRect(0, 0, this.dom.width, this.dom.height);
      this.dataModel.each((node: GraphBase) => {
        node.render();
      });
    }
  }
  drawEnd(node: GraphBase) {
    this.dataModel.add(node);
    this.setDrawInteractor(DrawTypeEnum.NO_DRAW);
    this.emit("drawEnd");
  }
  // 响应选中对象改变
  onSelectedChange(selectedObj: GraphBase) {
    this.selectedObj = selectedObj;
    this.emit("selectedChange", selectedObj);
  }
  // 响应选中对象属性改变
  onPropertyChange(propertyChangeObj: {
    propertyName: string;
    oldValue: any;
    newValue: any;
  }) {
    this.emit("propertyChange", propertyChangeObj);
  }
  // 改变选中对象的属性
  changeProperty(changeObj: { propertyName: string; propertyValue: any }) {
    if (this.interactor instanceof SelectedInteractor) {
      this.interactor.changeProperty(
        changeObj.propertyName,
        changeObj.propertyValue
      );
    }
  }
  // 响应滚轮滚动事件
  onWheel(e: WheelEvent) {
    e.preventDefault();
    let zoom = 1;
    if (e.deltaY > 0) {
      // 滚轮向下滚动
      zoom = 0.9;
    } else if (e.deltaY < 0) {
      // 滚轮向上滚动
      zoom = 1.1;
    }
    this.zoom *= zoom;
    setScale(this.zoom);
    this.redraw();
    if (this.interactor instanceof SelectedInteractor) {
      this.interactor.drawControlPoints();
    }
  }
}
